﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Text;
using CSF.Utility.Misc;

namespace CSF.Utility.Mvc
{
    /// <summary>
    /// Author: Robin
    /// Create Date: 2011-4-12
    /// 构造树形的Html的类
    /// </summary>
    /// <typeparam name="T">用于构造树的对象类型</typeparam>
    /// <typeparam name="TKey">主键的类型</typeparam>
    public class TreeBuilder<T, TKey>
    {
        private List<T> _list;
        private Func<T, TKey> _keySelector;
        private Func<T, TKey> _parentSelector;
        private Func<T, bool, string> _nodeText;
        private TKey _root;

        private StringBuilder _stringBuilder = new StringBuilder();

        /// <summary>
        /// 构造树形的Html的类的构造函数
        /// </summary>
        /// <param name="list">用于构造树的数据列表</param>
        /// <param name="keySelector">主键字段</param>
        /// <param name="parentSelector">指向父节点的外键字段</param>
        /// <param name="nodeText">节点上输出的字符串</param>
        /// <param name="root">第一层节点的父节点</param>
        public TreeBuilder(IEnumerable<T> list,
            Func<T, TKey> keySelector,
            Func<T, TKey> parentSelector,
            Func<T, bool, string> nodeText,
            TKey root)
        {
            if (list != null)
                _list = list.ToList();
            _keySelector = keySelector;
            _parentSelector = parentSelector;
            _nodeText = nodeText;
            _root = root;
        }

        /// <summary>
        /// 非叶子节点上的Css类（应用于<li>）上
        /// </summary>
        public string NodeCssClass
        {
            get;
            set;
        }

        /// <summary>
        /// 叶子节点上的Css类（应用于<li>）上
        /// </summary>
        public string LeafCssClass
        {
            get;
            set;
        }

        /// <summary>
        /// 输出字符串
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return ToString(null);
        }

        /// <summary>
        /// 输出字符串
        /// </summary>
        /// <param name="htmlAttributes">在第一层<ul>上添加的html属性</param>
        /// <returns></returns>
        public string ToString(object htmlAttributes)
        {
            if (_list != null)
            {
                Func<T, bool> rootPredicate = p => { return _root == null && _parentSelector(p) == null || _root != null && _root.Equals(_parentSelector(p)); };

                if (_list.Any(rootPredicate))
                {
                    BuildTree(rootPredicate, htmlAttributes);
                }
            }
            return _stringBuilder.ToString();
        }

        /// <summary>
        /// 递归构造树形Html
        /// </summary>
        /// <param name="rootPredicate">是否为指定根的子节点的判断函数</param>
        /// <param name="htmlAttributes"><ul>上添加的html属性</param>
        private void BuildTree(Func<T, bool> rootPredicate, object htmlAttributes)
        {
            _stringBuilder.Append("<ul");
            AppendHtmlAttributes(htmlAttributes);
            _stringBuilder.AppendLine(">");

            var brothers = _list.Where(rootPredicate).ToArray();
            foreach (T t in brothers)
            {
                _list.Remove(t);
            }

            foreach (T t in brothers)
            {
                TKey root = _keySelector(t);
                Func<T, bool> nextPredicate = p => { return root == null && _parentSelector(p) == null || root != null && root.Equals(_parentSelector(p)); };
                _stringBuilder.Append("<li");
                bool isLeaf = !_list.Any(nextPredicate);
                AppendCssClass(isLeaf);
                _stringBuilder.AppendLine(">");
                _stringBuilder.AppendLine(_nodeText(t, isLeaf));
                    
                if (!isLeaf)
                    BuildTree(nextPredicate, null);
                _stringBuilder.Append("</li>");
            }

            _stringBuilder.Append("</ul>");
        }

        /// <summary>
        /// 添加的html属性
        /// </summary>
        /// <param name="htmlAttributes"></param>
        private void AppendHtmlAttributes(object htmlAttributes)
        {
            if (htmlAttributes != null)
            {
                var attrs = htmlAttributes.ToDictionary();
                foreach (var key in attrs.Keys)
                {
                    _stringBuilder.Append(' ');
                    _stringBuilder.Append(key);
                    _stringBuilder.Append('=');
                    _stringBuilder.Append('\"');
                    _stringBuilder.Append(attrs[key].ToString());
                    _stringBuilder.Append('\"');
                }
            }
        }

        /// <summary>
        /// 在<li>上添加Css类
        /// </summary>
        /// <param name="isLeaf"></param>
        private void AppendCssClass(bool isLeaf)
        {
            if (isLeaf)
            {
                if (!string.IsNullOrWhiteSpace(this.LeafCssClass))
                {
                    _stringBuilder.Append(" class=\"");
                    _stringBuilder.Append(this.LeafCssClass);
                    _stringBuilder.Append("\"");
                }
            }
            else
            {
                if (!string.IsNullOrWhiteSpace(this.NodeCssClass))
                {
                    _stringBuilder.Append(" class=\"");
                    _stringBuilder.Append(this.NodeCssClass);
                    _stringBuilder.Append("\"");
                }
            }
        }
    }
}